package net.oschina.soiff.translator;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 百度翻译引擎java示例代码
 */
@Slf4j
@RestController
public class Translator {

    private static final String UTF8 = "utf-8";

    @Value("${baidu.appid}")
    private String appId;
    @Value("${baidu.token}")
    private String token;
    @Value("${baidu.limit:1500000}")
    private int max;
    @Value("${baidu.from:en}")
    private String from;
    @Value("${baidu.to:zh}")
    private String to;

    @PostConstruct
    public void init() {
        log.info("Application information: limit -> {}, from -> {}, to -> {}", max, from, to);
    }

    private static final String url = "http://api.fanyi.baidu.com/api/trans/vip/translate";
    private static final Random random = new Random();

    private static AtomicInteger ai = new AtomicInteger(0);
    private static Map<String, String> cache = new HashMap<String, String>(0);
    private static ObjectMapper om = new ObjectMapper();

    @RequestMapping(value = "/translate")
    public String translate(String q) throws Exception {
        q = q.toLowerCase(Locale.GERMANY).trim();

        if (cache.containsKey(q)) {
            return cache.get(q);
        }

        if (ai.addAndGet(q.length()) > max) {
            log.warn("当月翻译字符数超过上线：{}", q);
            return null;
        }

        //用于md5加密
        int salt = random.nextInt(10000);
        //本演示使用指定的随机数为1435660288
        //int salt = 1435660288;

        // 对appId+源文+随机数+token计算md5值
        StringBuilder md5String = new StringBuilder();
        md5String.append(appId).append(q).append(salt).append(token);
        String md5 = DigestUtils.md5Hex(md5String.toString());

        //使用Post方式，组装参数
        HttpPost httpost = new HttpPost(url);
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("q", q));
        nvps.add(new BasicNameValuePair("from", from));
        nvps.add(new BasicNameValuePair("to", to));
        nvps.add(new BasicNameValuePair("appid", appId));
        nvps.add(new BasicNameValuePair("salt", String.valueOf(salt)));
        nvps.add(new BasicNameValuePair("sign", md5));
        httpost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));

        //创建httpclient链接，并执行
        CloseableHttpClient httpclient = HttpClients.createDefault();
        CloseableHttpResponse response = httpclient.execute(httpost);

        //对于返回实体进行解析
        HttpEntity entity = response.getEntity();
        InputStream returnStream = entity.getContent();
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(returnStream, UTF8));
        StringBuilder result = new StringBuilder();
        String str;
        while ((str = reader.readLine()) != null) {
            result.append(str).append("\n");
        }

        Map<String, Object> resp = om.readValue(result.toString(), HashMap.class);
        if (resp.containsKey("trans_result")) {
            List<Object> results = (List<Object>) resp.get("trans_result");
            if (results.size() > 0) {
                String dst = ((Map<String, String>) results.get(0)).get("dst");
                log.info("翻译成功：{} => {}", q, dst);
                cache.put(q, dst);
                return URLDecoder.decode(dst, UTF8);
            }
        }

        log.warn("翻译失败：{}", q);
        cache.put(q, null);
        return null;
    }
}

